#ifndef WF_NET_H
#define WF_NET_H

#include "bindings/binding.h"
#include "types/wfnettypes.h"

#include <btime.h>
#include <directedgraph.h>
#include <inet.h>

#include <QtCore/QHash>
#include <QtCore/QObject>

using namespace core;
using namespace net;

namespace wfnet
{
class Arc;
class Expression;
class Place;
class Transition;

class DynamicTypeManager;
class BatchJournal;
class NetRunnable;

class WfNet : public QObject, /*implements*/public INet
{
    Q_OBJECT

public:
    WfNet(QObject* parent = 0);
    ~WfNet();

    // INet
    void run(int repetitions);
    void pause();
    void stop();
    void stepForward();
    void stepBackward();
    void setSimulationSpeed(uint speed);

    bool isLocked() const;

    IPlace* addPlace(IColorSet* colorSet, QString name = QString(),
        nid id = nid());
    ITransition* addTransition(QString name = QString(),
        nid id = nid());
    IExpression* addExpression(const Expr& expr,
        const TypeName& context, nid id = nid(),
        bool timed = false);
    void removePlace(IPlace* place);
    void removeTransition(ITransition* transition);
    void removeExpression(IExpression* expression);

    IArc* connect(IPlace* source,
        ITransition* destination);
    IArc* connect(ITransition* source,
        IPlace* destination);
    void disconnect(IArc* arc);
    void disconnectAll(IPlace* place);
    void disconnectAll(ITransition* transition);

    IPlace* place(nid id) const;
    ITransition* transition(nid id) const;

    const DirectedGraph& getGraph() const;

    QSet<ColorSetName> registeredColorSets() const;
    QSet<VariableName> registeredVariables() const;

    ColorSetName variableType(const VariableName& name) const;
    bool isVariableTimed(const VariableName& name) const;

    void initialMarkingSet();
    void resetInitialMarking();

    BatchJournal* journal() const;
    QList<nid> places() const;

private:
    void registerColorSet(const ColorSetName& name);
    void registerVariable(const VariableName& name);

    void unregisterColorSet(const ColorSetName& name);
    void unregisterVariable(const VariableName& name);

    void determineEnabledTransitions();
    void fireRandomTransition();

    void saveInitialMarking();
    void deleteInitialMarking();
    void restoreInitialMarking();

    void createNewJournal();

    void emitFinished();

signals:
    void finished();

private:
    friend class BatchJournal;
    friend class DynamicTypeManager;
    friend class Journal;
    friend class NetRunnable;
    friend class NetRunner;

    uint m_speed;
    bool m_isLocked;
    BasicTime m_globalClock;
    QHash<Transition*, Binding> m_currentBinding;
    DirectedGraph m_graph;
    QHash<nid, Place* > m_places;
    QHash<nid, Transition* > m_transitions;
    QHash<nid, Arc* > m_arcs;
    QHash<nid, Expression* > m_expressions;
    QSet<ColorSetName> m_colorSets;
    QSet<VariableName> m_variables;
    QSet<Transition*> m_enabledTransitions;
    QHash<Place*, core::TypeValue> m_initialMarking;
    BatchJournal* m_journal;
};

} // namespace wfnet

#endif
